package com.rookie.shiro.module.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.rookie.shiro.module.constant.SecurityConstant;
import com.rookie.shiro.module.exception.SecretMismatchException;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author rookie
 */
@Slf4j
public class JwtUtils {

    private static final Map<String, String> SECRET = new LinkedHashMap<>();

    static {
        SECRET.put("app", "9a74333da7a-f0be-473f2-89c9-bd7430272c69");
        SECRET.put("pc", "a48552223e8-67a8-473fe-b390b-b82ec02badd1");
        SECRET.put("weChat", "519232a9fc0-4a79-43bb3-86e3-c9582cafbc4c");
        SECRET.put("mobile", "ec4c4ac4b-03812-49f3f-b6e6-998acd66b736");
    }

    /**
     * 生成token
     *
     * @param o          存取的用户信息
     * @param type       token类型
     * @param expireTime token有效时间
     * @return token
     */
    public static String sign(Object o, String type, long... expireTime) {
        Map<String, Object> map = new HashMap<>(3);
        map.put("alg", "HMA256");
        map.put("typ", "JWT");
        long nowDate = System.currentTimeMillis();
        Date date = new Date(nowDate);
        //生成签名
        final Algorithm signer = Algorithm.HMAC256(getSecret(type));
        JWTCreator.Builder builder = JWT.create()
                .withHeader(map)
                .withIssuer("rookie")
                .withIssuedAt(date)
                .withClaim(SecurityConstant.TOKEN_TYPE_NAME, type)
                .withClaim(SecurityConstant.TOKEN_USER_INFO_NAME, JsonUtils.getJsonString(o));
        if (expireTime.length > 0) {
            return builder.withExpiresAt(new Date(nowDate + expireTime[0])).sign(signer);
        } else {
            return builder.sign(signer);
        }

    }

    /**
     * TokenExpiredException token已过期
     * SignatureVerificationException 密钥出现问题
     * 其他异常则是token错误
     *
     * @param token     token
     */
    public static void verify(String token) {
        String type = getClaim(token, SecurityConstant.TOKEN_TYPE_NAME);

//        获取token的类型
        Algorithm algorithm = Algorithm.HMAC256(getSecret(type));
        JWTVerifier verifier = JWT.require(algorithm)
                .build();
        //效验TOKEN
        DecodedJWT jwt = verifier.verify(token);
    }


    public static String getClaim(String token, String claim) {
        DecodedJWT jwt = JWT.decode(token);
        // 只能输出String类型，如果是其他类型返回null
        return jwt.getClaim(claim).asString();
    }

    private static String getSecret(String type) {
        String s = SECRET.get(type);
        if (s == null) {
            log.error("密钥不存在");
            throw new SecretMismatchException("密钥不存在");
        }
        return s;
    }

}
